﻿using System;
using System.Data;
using System.Data.SqlClient;

namespace XJX.DBCore
{
    /// <summary>
    /// Class1 的摘要说明。
    /// </summary>
    public abstract class DBObject
    {
        protected SqlConnection Connection;//定义了两个字段级变量，此变量只能被继承类访问。
        private string connectionString;   //一个私有变量，只可以通过属性访问。

        /// <summary>
        /// 以下是一个构造函数，参数是传入的一个和数据库连接的字串。
        /// </summary>
        /// <param name="newConnectionString"></param>
        public DBObject(string newConnectionString)
        {
            connectionString = newConnectionString;  //作为一个返回的属性值
            Connection = new SqlConnection(connectionString);//创建一个连接对象
        }

        /// <summary>
        /// 以下是获取连接串的一个属性值。
        /// </summary>
        protected string ConnectionString
        {
            get
            {
                return connectionString;
            }
        }

        /// <summary>
        /// 以下段生成一个SqlCommand对象，它需要传入对应的后台数据库上的存储过程，并且传入存储过程的参数数组。
        /// </summary>
        /// <param name="storedProcName"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        private SqlCommand BuildIntCommand(string storedProcName, IDataParameter[] parameters)
        {
            SqlCommand command = BuildQueryCommand(storedProcName, parameters);//调用下面的一个过程创建对象。			

            //以下语句加入一个自定义的参数，以实现对存储过程的数值返回值的存储。
            command.Parameters.Add(new SqlParameter("ReturnValue",
                SqlDbType.Int,
                4, /* Size */
                ParameterDirection.ReturnValue,
                false, /* is nullable */
                0, /* byte precision */
                0, /* byte scale */
                string.Empty,
                DataRowVersion.Default,
                null));

            command.Parameters.Add(new SqlParameter("ReturnFieldValue",
                SqlDbType.VarChar,
                1000, /* Size */
                ParameterDirection.Output,
                false, /* is nullable */
                0, /* byte precision */
                0, /* byte scale */
                string.Empty,
                DataRowVersion.Default,
                null));

            return command;
        }

        //不需要返回字段值时调用。
        private SqlCommand BuildIntCommand_1(string storedProcName, IDataParameter[] parameters)
        {
            SqlCommand command = BuildQueryCommand(storedProcName, parameters);//调用下面的一个过程创建对象。			

            //以下语句加入一个自定义的参数，以实现对存储过程的数值返回值的存储。
            command.Parameters.Add(new SqlParameter("ReturnValue",
                SqlDbType.Int,
                4, /* Size */
                ParameterDirection.ReturnValue,
                false, /* is nullable */
                0, /* byte precision */
                0, /* byte scale */
                string.Empty,
                DataRowVersion.Default,
                null));

            return command;
        }

        private SqlCommand BuildPageDataSetCommand(string storedProcName, IDataParameter[] parameters)
        {
            SqlCommand command = BuildQueryCommand(storedProcName, parameters);//调用下面的一个过程创建对象。			

            //以下语句加入一个自定义的参数，以实现对存储过程的数值返回值的存储。总计数据记录条数。
            command.Parameters.Add(new SqlParameter("TotalCount",
                SqlDbType.Int,
                4, /* Size */
                ParameterDirection.Output,
                false, /* is nullable */
                0, /* byte precision */
                0, /* byte scale */
                string.Empty,
                DataRowVersion.Default,
                null));


            //以下语句加入第二个自定义的参数，以实现对存储过程的数值返回值的存储。总计数据记录页数。
            command.Parameters.Add(new SqlParameter("PageCount",
                SqlDbType.Int,
                4, /* Size */
                ParameterDirection.Output,
                false, /* is nullable */
                0, /* byte precision */
                0, /* byte scale */
                string.Empty,
                DataRowVersion.Default,
                null));

            return command;
        }

        /// <summary>
        /// 从上面的过程进行调用，返回一个对象，传入的参数与上面的相同。
        /// </summary>
        /// <param name="storedProcName"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        private SqlCommand BuildQueryCommand(string storedProcName, IDataParameter[] parameters)
        {
            SqlCommand command = new SqlCommand(storedProcName, Connection);
            command.CommandType = CommandType.StoredProcedure;

            //添加SqlCommand对象的所有参数，也就是存储过程的所需参数。
            foreach (SqlParameter parameter in parameters)
            {
                command.Parameters.Add(parameter);
            }

            return command;

        }

        /// <summary>
        /// 以下过程有三个参数，前两个与上面的过程一致，第三个参数返回执行结果所影响的数据行数，另外这个过程本身也
        /// 可以返回一个值，那么也就是说这个过程可以返回三个值。(一个是受影响行数，另一个通常是返回插入记录的ＩＤ号)这个过程是调用上面的过程。
        /// </summary>
        /// <param name="storedProcName"></param>
        /// <param name="parameters"></param>
        /// <param name="rowsAffected"></param>
        /// <returns></returns>
        protected int RunProcedure(string storedProcName, IDataParameter[] parameters, out int rowsAffected, out string ReturnFieldValue)
        {
            int result;
            
            Connection.Open();
            SqlCommand command = BuildIntCommand(storedProcName, parameters);
            rowsAffected = command.ExecuteNonQuery();
            result = (int)command.Parameters["ReturnValue"].Value;
            ReturnFieldValue = (string)command.Parameters["ReturnFieldValue"].Value;
            Connection.Close();
            return result;
        }

        //和上面的方法差不多，只是应用在不需要返回字段值时。
        protected int RunProcedure(string storedProcName, IDataParameter[] parameters, out int rowsAffected)
        {
            int result;

            Connection.Open();
            SqlCommand command = BuildIntCommand_1(storedProcName, parameters);//这一句调用不一样。
            rowsAffected = command.ExecuteNonQuery();
            result = (int)command.Parameters["ReturnValue"].Value;
            Connection.Close();
            return result;
        }



        /// <summary>
        /// 此方法是上面方法的重载方法，只是返回的值不同，得到一个只读，向前数据集,在调用时还需要关闭它。
        /// </summary>
        /// <param name="storedProcName"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        protected SqlDataReader RunProcedure(string storedProcName, IDataParameter[] parameters)
        {
            SqlDataReader returnReader;

            Connection.Open();
            SqlCommand command = BuildPageDataSetCommand(storedProcName, parameters);
            command.CommandType = CommandType.StoredProcedure;

            returnReader = command.ExecuteReader(CommandBehavior.CloseConnection);
            return returnReader;
        }

        /// <summary>
        /// 此方法是上面方法的重载方法，只是返回的值不同，得到一个DataSet数据集。
        /// 注意它利用了SqlDataAdapter中的一个属性，它可以自动创建四个SQL语句，select 语句是其中一个，
        /// 所以可以把SqlCommand对象传送给他的一个属性。
        /// </summary>
        /// <param name="storedProcName"></param>
        /// <param name="parameters"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        protected DataSet RunProcedure(string storedProcName, IDataParameter[] parameters, string tableName)
        {
            DataSet dataSet = new DataSet();
            Connection.Open();
            SqlDataAdapter sqlDA = new SqlDataAdapter();
            sqlDA.SelectCommand = BuildQueryCommand(storedProcName, parameters);//这一语句是关键性的。
            sqlDA.Fill(dataSet, tableName);
            Connection.Close();

            return dataSet;
        }

        /// <summary>
        /// 这是第四个重载方法。
        /// </summary>
        /// <param name="storedProcName"></param>
        /// <param name="parameters"></param>
        /// <param name="dataSet"></param>
        /// <param name="tableName"></param>
        protected void RunProcedure(string storedProcName, IDataParameter[] parameters, DataSet dataSet, string tableName)
        {
            Connection.Open();
            SqlDataAdapter sqlDA = new SqlDataAdapter();
            sqlDA.SelectCommand = BuildIntCommand(storedProcName, parameters);
            sqlDA.Fill(dataSet, tableName);
            Connection.Close();
        }

        ///第五个重载方法
        ///主要解决存储过程分页调用，并返回参数(记录总数、页码总数）
        ///
        protected DataSet RunProcedure(string storedProcName, IDataParameter[] parameters, string tableName,out int PageCount,out int TotalCount)
        {
            //TotalCount INT OUTPUT,      --返回总记录
            //TotalPageCount INT OUTPUT   --返回总页数

            SqlCommand command = BuildPageDataSetCommand(storedProcName, parameters);

            DataSet dataSet = new DataSet();
            Connection.Open();
            SqlDataAdapter sqlDA = new SqlDataAdapter();
            sqlDA.SelectCommand = command;
            sqlDA.Fill(dataSet, tableName);

            object o = command.Parameters["TotalCount"].Value;
            TotalCount = (o == null || o == DBNull.Value) ? 0 : System.Convert.ToInt32(o);

            object b = command.Parameters["PageCount"].Value;
            PageCount = (b == null || o == DBNull.Value) ? 0 : System.Convert.ToInt32(b);

            Connection.Close();

            return dataSet;
        }

        ///第六个重载方法
        ///主要解决在获取查询信息的同时，返回值和关键字段值。
        ///
        protected DataSet RunProcedure(string storedProcName, IDataParameter[] parameters, string tableName, out int ReturnValue, out string ReturnFieldValue)
        {
            SqlCommand command = BuildIntCommand(storedProcName, parameters);

            DataSet dataSet = new DataSet();
            Connection.Open();
            SqlDataAdapter sqlDA = new SqlDataAdapter();
            sqlDA.SelectCommand = command;
            sqlDA.Fill(dataSet, tableName);

            ReturnValue = int.Parse(command.Parameters["ReturnValue"].Value.ToString());

            ReturnFieldValue = command.Parameters["ReturnFieldValue"].Value.ToString();

            Connection.Close();

            return dataSet;
        }

        ///第七个重载方法
        ///主要解决在获取查询信息的同时，返回值。
        ///
        protected DataSet RunProcedure(string storedProcName, IDataParameter[] parameters, string tableName, out int ReturnValue)
        {
            SqlCommand command = BuildIntCommand_1(storedProcName, parameters);

            DataSet dataSet = new DataSet();
            Connection.Open();
            SqlDataAdapter sqlDA = new SqlDataAdapter();
            sqlDA.SelectCommand = command;
            sqlDA.Fill(dataSet, tableName);

            ReturnValue = int.Parse(command.Parameters["ReturnValue"].Value.ToString());

            Connection.Close();

            return dataSet;
        }

    }
}
